<?php
/////////////////////
// LIBRARY - BEGIN //
/////////////////////

// utils
////////

session_start();

/**
 * Simple reference to location of this page.
 */
$here = basename(__FILE__);

/**
 * Return simple formatted specified variable
 *
 * @param misc $x
 * @return string simple formatted specified variable
 */
function pr($x) {
    echo '<pre>';
    print_r($x);
    echo '</pre>';
}

/**
 * Redirect to location specified.
 *
 * @param string $location absolute url of location
 */
function redirect($location) {
    header('Location: '.$location);
    exit();
}

/**
 * Returns true if $string is valid UTF-8 and false otherwise.
 *
 * @since        1.14
 * @param [mixed] $string     string to be tested
 * @subpackage
 */
function is_utf8($string) {
  
    // From http://w3.org/International/questions/qa-forms-utf-8.html
    return preg_match('%^(?:
          [\x09\x0A\x0D\x20-\x7E]            # ASCII
        | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
        |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
        |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
        |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
        | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
        |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
    )*$%xs', $string);
  
} 

// i18n
///////

/**
 * Return translated string if possible. If not, return same string.
 * 
 * @param string $s string to translate
 * @param string $locale i18n locale
 * @return translated word if possible, if not, same string.
 */
function __($s='', $locale=null) {
    global $DICTIONARY, $DEFAULT_LOCALE;
    $locale = $locale?$locale:$DEFAULT_LOCALE;
    return isset($DICTIONARY[$locale][$s])?$DICTIONARY[$locale][$s]:$s;
}

// core
///////

/**
 * Generic process.
 */
class Process {
    var $input;
    var $output;
    function setInput($input) {
        $this->input = $input;
        return $this;
    }
    function action() {
        return $this;
    }
    function doProcess($process) {
        return $process->setInput($this->input)->action();
    }
}

/**
 * Extends Process with a password.
 */
class SecureProcess extends Process {
    var $password = '';
    function setPassword($password) {
        $this->password = $password;
    }
    function isLogged() {
        return isset($_SESSION['kcwikilogged']) && $_SESSION['kcwikilogged'];
    }
    function login() {
        if ($this->isLogged()) {
            return true;
        }
        if (isset($this->input['password']) && sha1($this->input['password'])==$this->password) {
            $_SESSION['kcwikilogged'] = 1;
            return true;
        }
        return false;
    }
    function logout() {
        unset($_SESSION['kcwikilogged']);
        redirect($_SERVER['HTTP_REFERER']);
    }
}

/*
 * Helper to provide common html objects and util functions.
 */
class Html {
    /**
     * Return html code for select.
     * 
     * @return string html code for select
     * @param string $name name of element
     * @param array $items options
     * @param string $currentValue current value [optional]
     * @param string $attributes extra html attributes [optional]
     */
    function select($name, $items, $currentValue=null, $attributes=null) {
        $attributesTag = $attributes?' '.$attributes:'';
        $result = '<select name="'.$name.$attributesTag.'">';
        foreach ($items as $value=>$label) {
            $selectedTag = ($value==$currentValue)?' selected="true"':'';
            $result .= '<option value="'.$value.'"'.$selectedTag.'>'.$label.'</option>';
        }
        $result .= '</select>';
        return $result;
    }
    /**
     * Return html code for input text.
     * 
     * @return string html code for input text
     * @param string $name name of element
     * @param string $currentValue current value [optional]
     * @param string $attributes extra html attributes [optional]
     */
    function inputText($name, $currentValue=null, $attributes=null) {
        $valueTag = $currentValue?' value="'.$currentValue.'"':'';
        $attributesTag = $attributes?' '.$attributes:'';
        $result = '<input type="text" name="'.$name.'"'.$valueTag.$attributesTag.'/>';
        return $result;
    }
    /**
     * Return html code for input password.
     * 
     * @return string html code for input password
     * @param string $name name of element
     * @param string $currentValue current value [optional]
     * @param string $attributes extra html attributes [optional]
     */
    function inputPassword($name, $currentValue=null, $attributes=null) {
        $valueTag = $currentValue?' value="'.$currentValue.'"':'';
        $attributesTag = $attributes?' '.$attributes:'';
        $result = '<input type="password" name="'.$name.'"'.$valueTag.$attributesTag.'/>';
        return $result;
    }
    /**
     * Return html code for input hidden.
     * 
     * @return string html code for hidden text
     * @param string $name name of element
     * @param string $currentValue current value [optional]
     * @param string $attributes extra html attributes [optional]
     */
    function inputHidden($name, $currentValue=null, $attributes=null) {
        $valueTag = $currentValue?' value="'.$currentValue.'"':'';
        $attributesTag = $attributes?' '.$attributes:'';
        $result = '<input type="hidden" name="'.$name.'"'.$valueTag.$attributesTag.'/>';
        return $result;
    }
    /**
     * Return html code for textarea.
     * 
     * @return string html code for textarea
     * @param string $name name of element
     * @param string $currentValue current value [optional]
     * @param string $attributes extra html attributes [optional]
     */
    function textarea($name, $currentValue=null, $attributes=null) {
        $valueTag = $currentValue?$currentValue:'';
        $attributesTag = $attributes?' '.$attributes:'';
        $result = '<textarea name="'.$name.'"'.$attributesTag.'>'.$valueTag.'</textarea>';
        return $result;
    }
    /**
     * Return html code for submit button.
     * 
     * @return string html code for submit button
     * @param string $currentValue current value [optional]
     * @param string $attributes extra html attributes [optional]
     */
    function submit($currentValue=null, $attributes=null) {
        $valueTag = $currentValue?' value="'.$currentValue.'"':'';
        $attributesTag = $attributes?' '.$attributes:'';
        $result = '<input type="submit"'.$valueTag.$attributesTag.'/>';
        return $result;
    }
    /**
     * Return html code for reset button.
     * 
     * @return string html code for reset button
     * @param string $currentValue current value [optional]
     * @param string $attributes extra html attributes [optional]
     */
    function reset($currentValue=null, $attributes=null) {
        $valueTag = $currentValue?' value="'.$currentValue.'"':'';
        $attributesTag = $attributes?' '.$attributes:'';
        $result = '<input type="reset"'.$valueTag.$attributesTag.'/>';
        return $result;
    }
    /**
     * Return html code for button.
     * 
     * @return string html code for button
     * @param string $currentValue current value [optional]
     * @param string $attributes extra html attributes [optional]
     */
    function button($currentValue=null, $attributes=null) {
        $valueTag = $currentValue?' value="'.$currentValue.'"':'';
        $attributesTag = $attributes?' '.$attributes:'';
        $result = '<input type="button"'.$valueTag.$attributesTag.'/>';
        return $result;
    }
    /**
     * Return html code for file input
     * 
     * @return string html code for file input
     * @param string $name name
     * @param string $attributes extra html attributes [optional]
     */
    function inputFile($name=null, $attributes=null) {
        $nameTag = $name?' name="'.$name.'"':'';
        $attributesTag = $attributes?' '.$attributes:'';
        $result = '<input type="file"'.$nameTag.$attributesTag.'/>';
        return $result;
    }
    /**
     * Return html code link
     * 
     * @return string html code for link
     * @param string $label label
     * @param string $url url
     * @param string $attributes extra html attributes [optional]
     */
    function link($url=null, $label=null, $attributes=null) {
        $label = $label?$label:$url;
        $attributesTag = $attributes?' '.$attributes:'';
        $result = '<a href="'.$url.'"'.$attributesTag.'/>'.$label.'</a>';
        return $result;
    }
}// end Html

///////////////////
// LIBRARY - END //
///////////////////

//////////////////////////////
// SPECIFIC LIBRARY - BEGIN //
//////////////////////////////

// i18n
///////

/**
 * Dictionary used for translations.
 */
$DICTIONARY['es'] = array (
'Already exists' => 'Ya existe',
'Cancel' => 'Cancelar',
'Current encode ISO-8859-1 will be converted to UTF-8' => 'El actual encode ISO-8859-1 será convertido a UTF-8',
'Delete' => 'Eliminar',
'Deleted' => 'Eliminado',
'Edit' => 'Editar',
'Invalid file type' => 'Tipo no válido',
'Licence' => 'Licencia',
'List' => 'Lista',
'No file' => 'No se encuentra el archivo',
'No undeletable' => 'No recuperable',
'No valid file name' => 'Nombre de archivo no válido',
'No valid login' => 'Login no válido',
'Purge' => 'Purgar',
'Rename' => 'Renombrar',
'Reset' => 'Deshacer',
'Save' => 'Guardar',
'Saving file problem' => 'Problema al guardar el archivo',
'Search' => 'Buscar',
'To create this page use Edit' => 'Para crear esta página, use Editar',
'To rename this page name use Save' => 'Para renombrar esta página, use Guardar',
'To save this page use Save' => 'Para guardar esta página, use Guardar',
'Undelete' => 'Recuperar',
'Undeleted' => 'Recuperado',
'Upload' => 'Subir archivo',
'Uploaded' => 'Subido archivo',
);

// theme
////////

/**
 * Available themes
 */
$themes['default'] = '
    body {
        font-family: Arial, Helvetica, sans-serif;
        font-size: 10pt;
        margin: 0px 100px 0px 100px;
        background-color: #abc;
    }
    h1 {
        margin: 0;
        color: #f80;
        border-bottom: 1px solid #f80;
    }
    h2 {
        margin: 0;
    }
    h3 {
        margin: 0;
    }
    a {
        text-decoration: none;
    }
    a:hover {
        text-decoration: underline;
    }
    ul {
        margin: 0;
        padding-left: 1em;
    }
    ol {
        margin: 0;
        padding-left: 1em;
    }
    form {
        display: inline;
    }
    input[type=text] {
        font-family: Arial, Helvetica, sans-serif;
        font-size: 10pt;
    }
    input[type=submit] {
        font-family: Arial, Helvetica, sans-serif;
        font-size: 8pt;
        font-weight: normal;
    }
    input[type=submit].renameButton {
        position: absolute;
        right: 110px;
    }
    input[type=reset] {
        font-family: Arial, Helvetica, sans-serif;
        font-size: 8pt;
        font-weight: normal;
    }
    input[type=button] {
        font-family: Arial, Helvetica, sans-serif;
        font-size: 8pt;
        font-weight: normal;
    }
    input[type=file] {
        font-family: Arial, Helvetica, sans-serif;
        font-size: 8pt;
        font-weight: normal;
    }
    textarea.wikiEditBox {
        font-family: Arial, Helvetica, sans-serif;
        font-size: 10pt;
        width: 800px;
        height: 400px;
    }
    textarea.preEditBox {
        font-family: "Courier New", Courier, monospaced;
        font-size: 9pt;
        width: 800px;
        height: 400px;
    }
    .search {
        background-color: #cde;
        color: #000000;
        font-size: 10pt;
        padding: 5px;
        text-align: right;
        border-color: #bce;
        border-bottom-style: none;
        border-width: 1px;
        border-left-style: solid;
        border-left-width: 10px;
        border-right-color: #bce;
        border-right-style: solid;
        border-right-width: 1px;
    }
    .referers {
        background-color: #dee;
        color: #000000;
        font-size: 10pt;
        padding: 2px;
        border-color: #cde;
        border-bottom-style: solid;
        border-width: 1px;
        border-left-style: solid;
        border-left-width: 10px;
        border-right-color: #cde;
        border-right-style: solid;
        border-right-width: 1px;
    }
    .title {
        font-weight: bold;
        background-color: #fff;
        color: #000;
        font-family: Arial, Helvetica, sans-serif;
        font-size: 16pt;
        font-weight: bold;
        padding: 10px;
        border-color: #fea;
        border-bottom-style: solid;
        border-width: 1px;
        border-left-style: solid;
        border-left-width: 10px;
        border-right-color: #eee;
        border-right-style: solid;
        border-right-width: 1px;
    }
    .content {
        padding: 10px;
        background-color: #fff;
    }
    .footer {
        background-color: #fea;
        color: #000000;
        font-size: 8pt;
        text-align: right;
        padding: 2px 10px 2px 10px;
        border-color: #ed9;
        border-bottom-style: solid;
        border-width: 1px;
        border-left-style: solid;
        border-left-width: 10px;
        border-right-color: #ed9;
        border-right-style: solid;
        border-right-width: 1px;
    }
    .sign {
        background-color: #ed9;
        color: #ed9;
        font-family: Arial, Helvetica, sans-serif;
        font-size: 8pt;
        text-align: right;
        padding: 2px 10px 2px 10px;
        border-color: #dc8;
        border-left-style: solid;
        border-left-width: 10px;
        border-bottom-color: #dc8;
        border-bottom-style: solid;
        border-bottom-width: 1px;
        border-right-color: #dc8;
        border-right-style: solid;
        border-right-width: 1px;
    }
    .sign a {
        background-color: #ed9;
        color: #ed9;
    }
    .message {
        font-style: italic;
    }
    .emptyWikiReference {
        font-style: italic;
        font-weight: bold;
    }    
    .emptyPreReference {
        font-family: "Courier New", Courier, monospaced;
        font-style: italic;
        font-weight: bold;
    }    
    .emptyEvalReference {
        font-family: "Courier New", Courier, monospaced;
        font-style: italic;
        font-weight: bold;
    }    
    .circularReference {
        font-weight: bold;
    }
    .emptyWikiInclude {
        font-size: 12pt;
        font-weight: bold;
        font-style: italic;
        color: #33f;
        margin-left: 1em;
    }    
    .emptyPreInclude {
        font-family: "Courier New", Courier, monospaced;
        font-style: italic;
        font-weight: bold;
    }    
    .emptyEvalInclude {
        font-family: "Courier New", Courier, monospaced;
        font-style: italic;
        font-weight: bold;
    }    
    .wikiBlock {
        margin-left: 1em;
        padding: 5px;
    }
    .wikiBlockReference {
        font-size: 12pt;
        font-weight: bold;
        color: #33f;
    }
    .wikiReference {
    }
    .wikiText {
    }
    .preBlock {
        margin-left: 1em;
        font-family: "Courier New", Courier, monospaced;
        font-size: 9pt;
        color: #0f0;
        background-color: #000;
        padding: 5px;
    }
    .preBlockReference {
        font-size: 10pt;
        color: #f00;
    }
    .preReference {
        font-size: 9pt;
        font-family: "Courier New", Courier, monospaced;
    }
    .preText {
        font-family: "Courier New", Courier, monospaced;
        font-size: 9pt;
    }
    .passwordBox {
        display: inline;
        font-size: 10pt;
        font-weight: normal;
    }
    .password {
        border: 1px solid #f88;
    }
    .message {
        background-color: #ff0;
        border-bottom: 1px solid #ee9;
        padding: 1px;
        text-align: center;
    }
';
$themes['red'] = '
    body {
        color: red;
    }
';


// constants
////////////

$DEFAULT_LOCALE = 'es';
$DEFAULT_THEME = 'default';
$DEFAULT_ACTION = 'view';
$DEFAULT_PAGE = 'Index';
$DEFAULT_INPUT = array(
    'action' => $DEFAULT_ACTION,
    'page' => $DEFAULT_PAGE
);
$PASSWORD = sha1('admin');


// objects
//////////
class Wiki extends SecureProcess {
    var $ICON = '/';
    
    // overwriting default action
    function action() {
        call_user_func(array($this, $this->input['action']));
        return $this;
    }
    
    /**
     * Set output view of input page and return it.
     * 
     * @return output view 
     */
    function view() {
        $page = $this->input['page'];
        $output['page'] = $page;
        $output['title'] = $page;
        
        if (isset($this->input['password'])) {
            if ($this->input['password'] && !$this->login()) {
                $output['message'] = __('No valid login');
            }
        }
        
        if (file_exists($page)) {
            $output['referers'] = $this->getReferers($page);
            $output['view'] = $this->_view($page);
        } else {
            $output['view'] = '';
            $output['message'] = __('To create this page use Edit');
        }
        $this->output = $output;
        return $this;
    }
    
    function getReferers($page) {
        global $here;
        $referers = array();
        $search = '/(\[\[|\{\{|\(\()'.$page.'/';
        $dh = opendir ('./');
        $i = 0;
        while ($filename = readdir ($dh)) {
            if ($filename!="." 
                && $filename!=".." 
                && in_array(pathinfo($filename, PATHINFO_EXTENSION), array('', 'wiki'))) {
                @$filecontent = file_get_contents($filename);
                if (preg_match($search, $filecontent)) {
                    $referers[$i]['page'] = $filename;
                    $referers[$i]['url'] = $here.'?page='.$filename;
                    $i++;
                }
            }
        }
        closedir ($dh);
        return $referers;
    }
    
    function _view($page) {
        $type_ = explode('.', $page);
        $type = isset($type_[1])?'.'.$type_[1]:'.wiki';
        switch ($type) {
            case '.wiki':
                $result = $this->parse($page);
                break;
            case '.txt':
            default:
                $result = '<pre class="preBlock">'.$this->parseText($page).'</pre>';
                break;
        }
        return $result;
    }
    
    function _content($page) {
        $content = file_get_contents($page);
        // prevent magic quotes
        if (get_magic_quotes_gpc()) {
            $content = stripslashes($content);
        }
//      if (!mb_check_encoding($content, 'UTF-8')) {
//          $content = mb_convert_encoding($content, 'UTF-8');
//      }
        if (!is_utf8($content)) {
            $content = utf8_encode($content);
        }
        if (is_utf8($content)) {
            $encode = 'UTF-8';
        } else {
            $encode = 'ISO-8859-1';
            $content = utf8_encode($content);
        }
        return htmlentities($content, ENT_NOQUOTES, $encode);// if use before comment encode to utf8
    }
    
    function _contentEncode($page) {
        $content = file_get_contents($page);
        // prevent magic quotes
        if (get_magic_quotes_gpc()) {
            $content = stripslashes($content);
        }
//      if (!mb_check_encoding($content, 'UTF-8')) {
//          $content = mb_convert_encoding($content, 'UTF-8');
//          $encode = 'UTF-8';
//      } else {
//          $encode = 'ISO-8859-1';
//      }
        if (is_utf8($content)) {
            $encode = 'UTF-8';
        } else {
            $encode = 'ISO-8859-1';
            //$content = utf8_encode($content);
        }
        //return array(htmlentities($content, ENT_NOQUOTES, 'UTF-8'), $encode);
        return array(htmlentities($content, ENT_NOQUOTES, $encode), $encode);// if use before comment encode to utf8
    }
    
    /**
     * Load file content of page and return it, or empty, if not exists.
     * 
     * @return output content
     */
    function edit() {
        $page = $this->input['page'];
        $output['page'] = $page;
        $output['title'] = $page;
        if (file_exists($page)) {
            list($output['content'], $output['encode']) = $this->_contentEncode($page);
            if ($output['encode']!='UTF-8') {
                $output['message'] = __('Current encode ISO-8859-1 will be converted to UTF-8');
            }
            $output['view'] = $this->_view($page);
        } else {
            $output['content'] = '';
            $output['view'] = '';
        }
        $type_ = explode('.', $page);
        $type = isset($type_[1])?'.'.$type_[1]:'.wiki';
        switch ($type) {
            case '.wiki':
                $output['contentEditBoxClass'] = 'wikiEditBox';
                break;
            case '.txt':
            default:
                $output['contentEditBoxClass'] = 'preEditBox';
                break;
        }
        $this->output = $output;
        return $this;
    }
    
    /**
     * Save input content and return it, or empty, if not exists.
     * 
     * @return output content
     */
    function save() {
        $page = $this->input['page'];
        $output['page'] = $page;
        $output['title'] = $page;
        
        if ($this->isLogged()) {
            $content = $this->input['content'];
            if (get_magic_quotes_gpc()) {
                $content = stripslashes($content);
            }
            $file = fopen($page, 'w');
            fwrite($file, $content);
            fclose($file);
        } else {
            $output['message'] = __('No valid login');
        }
        if (file_exists($page)) {
            $output = array_merge($output, $this->view()->output);
        } else {
            $output['content'] = '';
            $output['view'] = '';
            $output['message'] = __('Saving file problem');
        }
        $this->output = $output;
        return $this;
    }
    
    /**
     * Load file content of page and return page name, or empty, if not exists.
     * 
     * @return output content
     */
    function editName() {
        $page = $this->input['page'];
        $output['page'] = $page;
        $output['title'] = $page;
        
        if (file_exists($page)) {
            $output = $this->view()->output;
        } else {
            $output['content'] = '';
            $output['view'] = '';
        }
        $this->output = $output;
        return $this;
    }
    
    /**
     * Rename page and return page new name, or empty, if not exists.
     * 
     * @return output content
     */
    function saveName() {
        $oldName = $this->input['page'];
        if (!file_exists($oldName)) {
            $output['content'] = '';
            $output['view'] = '';
            $output['message'] = __('No file').': '.$oldName;
            $this->output = $output;
            return $this;
        }
        $page = $this->input['newName'];
        if ( !preg_match('/^[a-zA-Z0-9_-]*$/', $page) ) {
            $output['message'] = __('No valid file name').': '.$page;
            $output = array_merge($output, $this->editName()->output);
            $this->input['action'] = 'editName';
            $this->output = $output;
            return $this;
        }
        if (!$this->isLogged()) {
            $output['message'] = __('No valid login');
            $output = array_merge($output, $this->view()->output);
            $this->output = $output;
            return $this;
        }
        // rename
        rename($oldName, $page);
            
        // update page references
        $dh = opendir ('./');
        while ($fname=readdir($dh)) {
            if ($fname!="." 
                && $fname!=".." 
                && (pathinfo($fname, PATHINFO_EXTENSION)=="" 
                    || pathinfo($fname, PATHINFO_EXTENSION)=="wiki")) {
                @$fcontent = file_get_contents($fname);
                $search = array(
                    '/\[\['.$oldName.'(\:"(.*)")?]]/U',            // links
                    '/\{\{'.$oldName.'(:"(.*)")?(:\'(.*)\')?}}/U', // block includes
                    '/\(\('.$oldName.'(:"(.*)")?(:\'(.*)\')?\)\)/U'// text includes
                );
                $replace = array(
                    "[[".$page."$1]]",
                    "{{".$page."$1$3}}",
                    "((".$page."$1$3))"
                );
                if (preg_match('/'.$oldName.'/', $fcontent)) {
                    $fcontent = preg_replace($search, $replace, $fcontent);
                }
                $fp = fopen($fname, "w");
                fwrite($fp, $fcontent);
            }
        }
        $this->input['page'] = $page;
        $output = $this->view()->output;
        $this->output = $output;
        return $this;
    }
    
    /**
     * Produces a list with all pages with searchstring ocurrences.
     */
    function search() {
        global $here;
        
        $page = $this->input['page'];
        $output['page'] = $page;
        $output['title'] = __('Search');
        
        $searchstring = $this->input['searchstring'];
        $output['searchstring'] = $this->input['searchstring'];

        $result = "";
        $search = '/'.$searchstring.'/i';
        $dh = opendir ('./');
        $searchList = array();
        while ($filename = readdir ($dh)) {
            if ($filename!="." 
                && $filename!=".." 
                && in_array(pathinfo($filename, PATHINFO_EXTENSION), array("", "txt", "eval"))) {
                @$filecontent = file_get_contents($filename);
                if (preg_match($search, $filecontent)) {
                    $searchList[] = $filename;
                }
            }
        }
        closedir ($dh);
        sort($searchList);
        $output['view']['searchList'] = $searchList;
        $this->output = $output;
        return $this;
    }
    
    /**
     * Produces a list with all files on current directory.
     */
    function listFiles() {
        global $here;
        
        $page = $this->input['page'];
        $output['page'] = $page;
        $output['title'] = __('List');
        
        $dh = opendir ('./');
        $filesList = array();
        while ($filename = readdir($dh)) {
            if ($filename!="." 
                && $filename!=".." 
                && in_array(pathinfo($filename, PATHINFO_EXTENSION), 
                    array("", "wiki", "txt", "eval", "gif", "jpg", "png", "zip", "deleted"))) {
                $filesList[$filename]['filename'] = $filename;
                $filesList[$filename]['extension'] = pathinfo($filename, PATHINFO_EXTENSION);
                $filesList[$filename]['openAction'] = '<a href="'.$filename.'">'.$filename.'</a>';
                if ( in_array(pathinfo($filename, PATHINFO_EXTENSION), 
                    array("", "wiki")) ) {
                    $filesList[$filename]['viewAction'] = '<a href="'.$here.'?page='.$filename.'">['.$filename.']</a>';
                } else {
                    $filesList[$filename]['viewAction'] = '&nbsp';
                }
                if (pathinfo($filename, PATHINFO_EXTENSION)=='deleted') {
                    $filesList[$filename]['deleteAction'] = '<a href="'.$here.'?page='.$page.'&filename='.$filename.'&action=undelete">['.__('Undelete').']</a>'.
                        '<a href="'.$here.'?page='.$page.'&filename='.$filename.'&action=purge">['.__('Purge').']</a>';
                } else {
                    $filesList[$filename]['deleteAction'] = '<a href="'.$here.'?page='.$page.'&filename='.$filename.'&action=delete">['.__('Delete').']</a>';
                }
            }
        }
        closedir ($dh);
        ksort($filesList);
        $output['view']['filesList'] = $filesList;
        $this->output = $output;
        return $this;
    }
    
    /**
     * Upload file.
     */
    function upload() {
        $allowedTypes = array(
            'image/gif', 'image/jpeg', 'image/pjpeg', 'image/png',
            'application/zip', 'text/plain'
        );
        $page = $this->input['page'];
        $output['page'] = $page;
        
        if ($this->isLogged()) {
            if (in_array($_FILES["file"]["type"], $allowedTypes)
                && ($_FILES["file"]["size"] < 50000)) {
                if ($_FILES["file"]["error"] > 0) {
                    echo __('Error').': '. $_FILES["file"]["error"]. "<br/>";
                } else {
                    if (file_exists($_FILES["file"]["name"])) {
                        $message = __('Already exists').': '.$_FILES["file"]["name"];
                    } else {
                        move_uploaded_file($_FILES["file"]["tmp_name"], $_FILES["file"]["name"]);
                        $message = __('Uploaded').': '.$_FILES["file"]["name"];
                        $message .= ' ['.$_FILES["file"]["type"]."]";
                        $message .= ' ['.($_FILES["file"]["size"])." B]";
                    }
                    $output['message'] = $message;
                }
            } else {
                $output['message'] = __('Invalid file type').': '.$_FILES["file"]["name"];
            }
        } else {
            $output['message'] = __('No valid login');
        }
        $this->output = array_merge($output, $this->listFiles()->output);
        return $this;
    }
    
    /**
     * Delete filename specified.
     */
    function delete() {
        $page = $this->input['page'];
        $filename = $this->input['filename'];
        $output['page'] = $page;
        if ($this->isLogged()) {
            if (file_exists($filename)) {
                if (file_exists($filename.".deleted")) {
                    unlink($filename.".deleted");
                }
                rename($filename, $filename.".deleted");
                $output['message'] = __('Deleted').': '.$filename;
            } else {
                $output['message'] = __('No file').': '.$filename;
            }
        } else {
            $output['message'] = __('No valid login');
        }
        $this->output = array_merge($output, $this->listFiles()->output);
        return $this;
    }
    
    /**
     * Undelete filename specified.
     */
    function undelete() {
        $page = $this->input['page'];
        $filename = $this->input['filename'];
        $output['page'] = $page;
        if ($this->isLogged()) {
            $originalName = pathinfo($filename, PATHINFO_FILENAME);
            if (file_exists($filename)) {
                rename($filename, $originalName);
                $output['message'] = __('Undeleted').': '.$originalName;
            } else {
                $output['message'] = __('No undeletable').': '.$originalName;
            }
        } else {
            $output['message'] = __('No valid login');
        }
        $this->output = array_merge($output, $this->listFiles()->output);
        return $this;
    }
    
    /**
     * Purge filename specified.
     */
    function purge() {
        $page = $this->input['page'];
        $filename = $this->input['filename'];
        $output['page'] = $page;
        if ($this->isLogged()) {
            if (file_exists($filename)) {
                unlink($filename);
            } else {
                $output['message'] = __('No file').': '.$filename;
            }
        } else {
            $output['message'] = __('No valid login');
        }
        $this->output = array_merge($output, $this->listFiles()->output);
        return $this;
    }
    
    /**
     * Return page content parsed.
     *
     * @param string $page page
     * @return string page content parsed
     */
    function parse($page) {
    
        /**
         * Return page content parsed.
         * Parsing is performed with this inner function to posibility recursivity.
         *
         * @param string $page page
         * @return string page content parsed
         */
        function doParse($page) {
            // $includedList store list of included pages to evite circular references
            global $includedList;
            $includedList = $includedList?$includedList:array();
            array_push($includedList, $page);

            if (file_exists($page)) {
                $content = file_get_contents($page);

                // replace html entities
                // UTF-8 support
//              if (!mb_check_encoding($content, 'UTF-8')) {
//                  $content = mb_convert_encoding($content, 'UTF-8');
//              }
                if (!is_utf8($content)) {
                    $content = utf8_encode($content);
                }
                
                $content = htmlspecialchars($content, ENT_NOQUOTES, 'UTF-8');
                
                // theme
                if (sizeof($includedList)>1) {
                    $search = "/\[\[theme:([A-Za-z0-9_-]*)]]([\s]\n)/U";
                    $content = preg_replace($search, '', $content);
                } else {
                    $search = "/\[\[theme:([A-Za-z0-9_-]*)]]([\s]\n)/U";
                    $content = preg_replace_callback($search, 'setTheme', $content);
                }

                // replace misc
                $search = array(
                    "/([\s]\n)?^- (.*)$/Um",					// ul (a)
                    "/<\/ul>\n<ul>/",							// ul (b)
                    "/([\s]\n)?^# (.*)$/Um",					// ol (a)
                    "/<\/ol>\n<ol>/",							// ol (b)
                    "/(.*)([\s]\n)###+([\s]\n|$)/U",			// h1
                    "/(.*)([\s]\n)===+([\s]\n|$)/U",			// h2
                    "/(.*)([\s]\n)---+([\s]\n|$)/U",			// h3
                    "/([\s]\n)/", 								// break line
                    "/\*\*(\S.*\S)\*\*/U",                      // bold
                    "/^\*\*(.*)$/m",                            // bold line
                    "/\/\/(\S([^\r]*)\S)\/\//U",                // italic
                    "/^\/\/(.*)$/m",                        // italic line
                    "/__(\S(.*)\S)__/U",                        // underline
                    "/^__(.*)$/m",                              // underline line
                    //"/ /", 									// space
                    "/\[\[http(s?):\/\/(.*)\:\"(.*)\"]]/U", 	// http & https
                    "/\[\[(http(s?)):\/\/(.*)]]/U",           	// http & https
                    "/\[\[ftp:\/\/(.*)\:\"(.*)\"]]/U",      	// ftp
                    "/\[\[(ftp):\/\/(.*)]]/U",                	// ftp
                    "/\[\[mailto:(.*)\:\"(.*)\"]]/U",       	// mailto
                    "/\[\[(mailto):(.*)]]/U",                 	// mailto
                    "/\[\[img:(.*)\:\"(.*)\":\'([a-z]*)\']]/U", // img
                    "/\[\[img:(.*)\:\'([a-z]*)\']]/U", 			// img
                    "/\[\[img:(.*)\:\"(.*)\"]]/U", 				// img
                    "/\[\[img:(.*)]]/U", 						// img
                    "/\[\[imgLeft:(.*)\:\"(.*)\"]]/U", 			// imgLeft
                    "/\[\[imgLeft:(.*)]]/U", 					// imgLeft
                    "/\[\[imgCenter:(.*)\:\"(.*)\"]]/U", 		// imgCenter
                    "/\[\[imgCenter:(.*)]]/U", 					// imgCenter
                    "/\[\[imgRight:(.*)\:\"(.*)\"]]/U", 		// imgRight
                    "/\[\[imgRight:(.*)]]/U", 					// imgRight
                );
                $replace = array(
                    "$1<ul><li>$2</li></ul>",
                    "",
                    "$1<ol><li>$2</li></ol>",
                    "",
                    "<h1>$1</h1>$3",
                    "<h2>$1</h2>$3",
                    "<h3>$1</h3>$3",
                    "<br/>$1",
                    "<b>$1</b>",
                    "<b>$1</b>",
                    "<i>$1</i>",
                    "<i>$1</i>",
                    "<u>$1</u>",
                    "<u>$1</u>",
                    //'&nbsp;',
                    "<a href=\"http$1://$2\">$3</a>",
                    "<a href=\"$1://$3\">$1://$3</a>",
                    "<a href=\"ftp://$1\">$2</a>",
                    "<a href=\"$1://$2\">$1://$2</a>",
                    "<a href=\"mailto:$1\">$2</a>",
                    "<a href=\"$1:$2\">$2</a>",
                    "<img src=\"$1\" title=\"$2\" align=\"$3\"/>",
                    "<img src=\"$1\" title=\"$1\" align=\"$2\"/>",
                    "<img src=\"$1\" title=\"$2\"/>",
                    "<img src=\"$1\" title=\"$1\"/>",
                    "<div style=\"text-align:left\"><img src=\"$1\" title=\"$2\"/></div>",
                    "<div style=\"text-align:left\"><img src=\"$1\" title=\"$1\"/></div>",
                    "<div style=\"text-align:center\"><img src=\"$1\" title=\"$2\"/></div>",
                    "<div style=\"text-align:center\"><img src=\"$1\" title=\"$1\"/></div>",
                    "<div style=\"text-align:right\"><img src=\"$1\" title=\"$2\"/></div>",
                    "<div style=\"text-align:right\"><img src=\"$1\" title=\"$1\"/></div>",
                );
                $content = preg_replace($search, $replace, $content);
                
                // replace wiki links
                $search = '/\[\[([A-Za-z0-9_-]*(\.[a-z_-]+)?)(\:"(.*)")?]]/U';
                $content = preg_replace_callback($search, 'replaceLinks', $content);

                // replace includes
                $search = '/\&lt\;\&lt\;(.*)\&gt\;\&gt\;/U';
                $content = preg_replace_callback($search, 'replaceUrlIncludes', $content);
                $search = '/\{\{([A-Za-z0-9_-]*(\.[a-z_-]+)?)(:"(.*)")?(:\'(.*)\')?}}/U';
                $content = preg_replace_callback($search, 'replaceBlockIncludes', $content);
                $search = '/\(\(([A-Za-z0-9_-]*(\.[a-z_-]+)?)(:"(.*)")?(:\'(.*)\')?\)\)/U';
                $content = preg_replace_callback($search, 'replaceIncludes', $content);
                
            } else {
                $content = '';
            }
            
            return $content;
        }
        
        /**
         * Return page content parsed.
         * Parsing is performed here to posibility recursivity.
         *
         * @param string $page page
         * @return string page content parsed
         */
        function doParseText($page) {
            // $includedList save list of included pages to evite circular references
            global $includedList;
            $includedList = $includedList?$includedList:array();
            array_push($includedList, $page);

            if (file_exists($page)) {
                $content = file_get_contents($page);

                // replace html entities
                // UTF-8 support
//              if (!mb_check_encoding($content, 'UTF-8')) {
//                  $content = mb_convert_encoding($content, 'UTF-8');
//              }
                if (!is_utf8($content)) {
                    $content = utf8_encode($content);
                }
                $content = htmlspecialchars($content, ENT_NOQUOTES, 'UTF-8');
                
                // theme
                if (sizeof($includedList)>1) {
                    $search = "/\[\[theme:([A-Za-z0-9_-]*)]]([\s]\n)/U";
                    $content = preg_replace($search, '', $content);
                } else {
                    $search = "/\[\[theme:([A-Za-z0-9_-]*)]]([\s]\n)/U";
                    $content = preg_replace_callback($search, 'setTheme', $content);
                }

                // replace misc
                $search = array(
                    "/([\s]\n)/", // break line
                    "/ /", // space
                );
                $replace = array(
                    "<br/>$1",
                    '&nbsp;',
                );
                $content = preg_replace($search, $replace, $content);
                                        
            } else {
                $content = '';
            }
            
            return $content;
        }
        
        /**
         * Callback funtion to preg_replace_callback.
         * Replace page link references to page with page link.
         * Also manage empty reference.
         *
         * @param array $matches matches array
         */
        function replaceLinks($matches) {
            global $here;
            $page = isset($matches[1])?$matches[1]:'';
            // some machines matches[2] is empty, some machines matches[2]=matches[2], I don't know why
            $type = (isset($matches[2]) && ($matches[1]!=$matches[2]))?($matches[2]?$matches[2]:'.wiki'):'.wiki';
            switch ($type) {
                case '.wiki':
                    $classTag = file_exists($page)?' class="wikiReference"':' class="emptyWikiReference"';
                    break;
                case '.txt':
                default:
                    $classTag = file_exists($page)?' class="preReference"':' class="emptyPreReference"';
                    break;
            }
            if (isset($matches[4])) {
                $label = $matches[4];
                $result = '<a href="'.$here.'?page='.$page.'"'.$classTag.'>'.$label.'</a>';;
            } else {
                $result = '<a href="'.$here.'?page='.$page.'"'.$classTag.'>'.$page.'</a>';
            }
            return $result;
        }
        
        /**
         * Callback funtion to preg_replace_callback.
         * Replace includes references to url with page content
         * Also prevent empty or circular reference.
         *
         * @param array $matches matches array
         */
        function replaceUrlIncludes($matches) {
            //pr($matches);
            $page = isset($matches[1])?$matches[1]:'';
            //$url = 'http://127.0.0.1/';
            $fh = fopen($url, 'r');
            $content = '';
            while (false !== ($c=fgetc($fh)))  {
                $content .= $c;
            }
            return $content;
        }
        
        /**
         * Callback funtion to preg_replace_callback.
         * Replace includes references to page with page content as block.
         * Also prevent empty or circular reference.
         *
         * @param array $matches matches array
         */
        function replaceBlockIncludes($matches) {
            global $input, $includedList, $here;
            $page = isset($matches[1])?$matches[1]:'';
            // some machines matches[2] is empty, some machines matches[2]=matches[2], I don't know why
            $type = (isset($matches[2]) && ($matches[1]!=$matches[2]))?($matches[2]?$matches[2]:'.wiki'):'.wiki';
            $label = (isset($matches[4]) && $matches[4])?$matches[4]:$page;
            $styleTag = isset($matches[6])?' style="'.$matches[6].'"':'';
            $content = '';
            switch ($type) {
                case '.wiki':
                    if (file_exists($page)) {
                        $content .= '<div class="wikiBlock"'.$styleTag.'>';
                        if (!in_array($page, $includedList)) {
                            $content .= '<div><a href="'.$here.'?page='.$page.'" class="wikiBlockReference">'.$label.'</a></div>';
                            $content .= doParse($page);
                            array_pop($includedList);
                        } else {
                            $content .= '<a href="'.$here.'?page='.$page.'" class="circularReference">'.$label.'</a>';
                        }
                        $content .= '</div>';
                    } else {
                        $content .= '<div><a href="'.$here.'?page='.$page.'" class="emptyWikiInclude">'.$label.'</a><div>';
                    }
                    break;
                case '.eval':
                    if (file_exists($page)) {
                        $content .= '<div class="wikiBlock"'.$styleTag.'>';
                        $content .= '<div><a href="'.$here.'?page='.$page.'" class="preBlockReference">'.$label.'</a></div>';
                        try {
                            $result = file_get_contents($page);
                            eval($result);
                            $content .= $output;
                        } catch(Exception $e) {
                            $content .= __('Exception').': '.$e->getMessage();
                        }
                        $content .= '</div>';
                    } else {
                        $content .= '<div class="wikiBlock"'.$styleTag.'>';
                        $content .= '<a href="'.$here.'?page='.$page.'" class="emptyEvalInclude">'.$label.'</a>';
                        $content .= '</div>';
                    }
                    break;
                case '.txt':
                default:
                    if (file_exists($page)) {
                        $content .= '<pre class="preBlock"'.$styleTag.'>';
                        $content .= '<div><a href="'.$here.'?page='.$page.'" class="preBlockReference">'.$label.'</a></div>';
                        $content .= doParseText($page);
                        array_pop($includedList);
                        $content .= '</pre>';
                    } else {
                        $content .= '<div><a href="'.$here.'?page='.$page.'" class="emptyPreInclude">'.$label.'</a><div>';
                    }
                    break;
            }
            return $content;
        }
    
        /**
         * Callback funtion to preg_replace_callback.
         * Replace includes references to page with page content inline.
         * Also prevent empty or circular reference.
         *
         * @param array $matches matches array
         */
        function replaceIncludes($matches) {
            global $input, $includedList, $here;
            $page = isset($matches[1])?$matches[1]:'';
            // some machines matches[2] is empty, some machines matches[2]=matches[2], I don't know why
            $type = (isset($matches[2]) && ($matches[1]!=$matches[2]))?($matches[2]?$matches[2]:'.wiki'):'.wiki';
            $label = (isset($matches[4]) && $matches[4])?$matches[4]:$page;
            $styleTag = isset($matches[6])?' style="'.$matches[6].'"':'';
            $content = '';
            switch ($type) {
                case '.wiki':
                    if (file_exists($page)) {
                        $content .= '<span class="wikiText"'.$styleTag.'>';
                        if (!in_array($page, $includedList)) {
                            $content .= doParse($page);
                            array_pop($includedList);
                        } else {
                            $content .= '<a href="'.$here.'?page='.$page.'" class="circularReference">'.$label.'</a>';
                        }
                        $content .= '</span>';
                    } else {
                        $content .= '<a href="'.$here.'?page='.$page.'" class="emptyWikiInclude">'.$label.'</a>';
                    }
                    break;
                case '.eval':
                    if (file_exists($page)) {
                        try {
                            $result = file_get_contents($page);
                            eval($result);
                            $content .= $output;
                        } catch(Exception $e) {
                            $content .= __('Exception').': '.$e->getMessage();
                        }
                    } else {
                        $content .= '<a href="'.$here.'?page='.$page.'" class="emptyEvalInclude">'.$label.'</a>';
                    }
                    break;
                case '.txt':
                default:
                    if (file_exists($page)) {
                        $content .= '<span class="preText"'.$styleTag.'>';
                        $content .= doParseText($page);
                        array_pop($includedList);
                        $content .= '</span>';
                    } else {
                        $content .= '<a href="'.$here.'?page='.$page.'" class="emptyPreInclude">'.$label.'</a>';
                    }
                    break;
            }
            return $content;
        }
        
        /**
         * Callback funtion to preg_replace_callback.
         * Use theme reference to set theme.
         *
         * @param array $matches matches array
         */
        function setTheme($matches) {
            global $DEFAULT_THEME, $themes, $theme, $themeCss;
            $themeSel = isset($matches[1])?$matches[1]:$DEFAULT_THEME;
            $themeCss = isset($themes[$themeSel])?$themes[$themeSel]:'';
            return '';
        }
        
        $content = doParse($page);
        return $content;
    }
    
    /**
     * Return page content parsed.
     *
     * @param string $page page
     * @return string page content parsed
     */
    function parseText($page) {
        /**
         * Callback funtion to preg_replace_callback.
         * Use theme reference to set theme.
         *
         * @param array $matches matches array
         */
        function setTheme($matches) {
            global $DEFAULT_THEME, $themes, $theme, $themeCss;
            $themeSel = isset($matches[1])?$matches[1]:$DEFAULT_THEME;
            $themeCss = isset($themes[$themeSel])?$themes[$themeSel]:'';
            return '';
        }
        
        if (file_exists($page)) {
            $content = file_get_contents($page);

            // replace html entities
            // UTF-8 support
            $content = htmlentities($content, ENT_NOQUOTES, 'UTF-8');
            
            // theme
            $search = "/\[\[theme:([A-Za-z0-9_-]*)]]([\s]\n)/U";
            $content = preg_replace_callback($search, 'setTheme', $content);

            // replace misc
            $search = array(
                "/([\s]\n)/", // break line
                "/ /", // space
            );
            $replace = array(
                "<br/>$1",
                '&nbsp;',
            );
            $content = preg_replace($search, $replace, $content);
                                    
        } else {
            $content = '';
        }
        
        return $content;
    }
    
}
        
////////////////////////////
// SPECIFIC LIBRARY - END //
////////////////////////////

///////////////////////
// MAIN CODE - BEGIN //
///////////////////////

// ingredients
$html = new Html();
$wiki = new Wiki();
$wiki->setPassword($PASSWORD);

// setting input
$input = $_POST?$_POST:($_GET?$_GET:$DEFAULT_INPUT);
$input['action'] = isset($input['action'])?$input['action']:$DEFAULT_ACTION;
$theme = isset($input['theme'])?$input['theme']:$DEFAULT_THEME;
$themeCss = $themes[$theme];
$DEFAULT_LOCALE = isset($input['locale'])?$input['locale']:$DEFAULT_LOCALE;

// do process
$wiki = $wiki->setInput($input)->action();
$input = $wiki->input;
$output = $wiki->output;

/////////////////////
// MAIN CODE - END //
/////////////////////
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title><?php echo $output['title'] ?></title>
    
    <?php
		echo '<style type="text/css">';
		echo $themeCss;
		echo '</style>';
	?>
    <script type="text/javascript">
        function editCancel() {
            window.location.href = '<?php echo $here.'?page='.$output['page'] ?>';
        }
    </script>
    
</head>

<body>
        <div class="header">
            <?php if (isset($output['message'])) { ?>
                <div class="message">
                    <?php echo $output['message']?>
                </div>
            <?php } ?>
            <div class="search">
                <?php
                if ($wiki->isLogged()) {
                    ?>
                    <form action="<?php echo $here?>" method="post">
                        <?php echo $html->inputHidden('action', 'logout')?>
                        <?php echo $html->inputHidden('page', $output['page'])?>
                        <?php echo $html->submit(__('Logout'))?>
                    </form>
                    <?php
                } else {
                    ?>
                    <form action="<?php echo $here?>" method="post">
                        <?php echo $html->inputHidden('action', 'view')?>
                        <?php echo $html->inputHidden('page', $output['page'])?>
                        <?php echo $html->inputPassword('password', '')?>
                        <?php echo $html->submit(__('Login'))?>
                    </form>
                    <?php
                }
                ?>
                <?php echo $html->link($here.'?page='.$output['page'].'&action=listFiles', __('List'))?>
                <form action="<?php echo $here?>" method="post">
                    <?php echo $html->inputHidden('action', 'search')?>
                    <?php echo $html->inputHidden('page', $output['page'])?>
                    <?php echo $html->inputText('searchstring', isset($output['searchstring'])?$output['searchstring']:'')?>
                    <?php echo $html->submit(__('Search'))?>
                </form>
            </div>
            <div class="referers">
                <?php echo $html->link($here, $wiki->ICON, 'class="wikiIcon"')?>
                <?php
                if (isset($output['referers'])) {
                    foreach ($output['referers'] as $referer) {
                        ?>
                        | <?php echo $html->link($referer['url'], $referer['page'], 'class="refererLink"')?>
                        <?php
                    }
                }
                ?>
            </div>
    <?php
    switch ($input['action']) {
        case 'view'     : // --------------------------------------------------
        case 'save'     : // --------------------------------------------------
        case 'saveName' : // --------------------------------------------------
        ?>
            <div class="title">
                <?php echo $html->link($here.'?page='.$output['page'], $output['title'])?>
                <?php if ($wiki->isLogged()) { ?>
                    <form action="<?php echo $here?>" method="post">
                        <?php echo $html->inputHidden('action', 'editName')?>
                        <?php echo $html->inputHidden('page', $output['page'])?>
                        <?php echo $html->submit(__('Rename'), 'class="renameButton"')?>
                    </form>
                <?php } ?>
            </div>
        </div>
        <div class="content">
            <?php if (isset($output['view'])) { ?>
                <?php if ($wiki->isLogged()) { ?>
                    <form action="<?php echo $here?>" method="post">
                        <?php echo $html->inputHidden('action', 'edit')?>
                        <?php echo $html->inputHidden('page', $output['page'])?>
                        <?php echo $html->submit(__('Edit'))?>
                    </form>
                <?php } ?>
                <div class="view">
                    <?php echo $output['view']?>
                </div>
                <?php if ($wiki->isLogged()) { ?>
                    <form action="<?php echo $here?>" method="post">
                        <?php echo $html->inputHidden('action', 'edit')?>
                        <?php echo $html->inputHidden('page', $output['page'])?>
                        <?php echo $html->submit(__('Edit'))?>
                    </form>
                <?php } ?>
            <?php } ?>
        </div>
        <?php break; // break case view ?>
        <?php
        case 'search'   : // --------------------------------------------------
        ?>
            <div class="title">
                <?php echo __('Search')?>
            </div>
        </div>
        <div class="content">
            <?php if (isset($output['view'])) { ?>
                <div class="view">
                    <ul>
                    <?php
                        foreach ($output['view']['searchList'] as $filename) {
                            echo "<li><a href=\"".$here."?page=".$filename."\">".$filename."</a></li>\n";
                        }
                    ?>
                    </ul>
                </div>
            <?php } ?>
        </div>
        <?php break; // break case search ?>
        <?php
        case 'listFiles': // --------------------------------------------------
        case 'upload'   : // --------------------------------------------------
        case 'delete'   : // --------------------------------------------------
        case 'undelete' : // --------------------------------------------------
        case 'purge'    : // --------------------------------------------------
        ?>
            <div class="title">
                <?php echo __('List')?>
            </div>
        </div>
        <div class="content">
            <?php if (isset($output['view'])) { ?>
                <div class="view">
                    <table border="0" cellspacing="0" cellpadding="1">
                    <?php
                        foreach ($output['view']['filesList'] as $file) {
                            echo '<tr>';
                            echo '<td>'.$file['openAction'].'</td>';
                            echo '<td>'.$file['viewAction'].'</td>';
                            echo '<td>'.$file['deleteAction'].'</td>';
                            echo '</tr>';
                        }
                    ?>
                    </table>
                </div>
            <?php } ?>
            <div class="uploadBox">
                <form action="<?php echo $here?>" method="post" enctype="multipart/form-data">
                    <?php echo $html->inputHidden('page', $output['page'])?>
                    <?php echo $html->inputHidden('action', 'upload')?>
                    <?php echo $html->inputFile('file', 'size="100"')?>
                    <?php echo $html->submit(__('Upload'))?>
                </form>
            </div>
        </div>
        <?php break; // break case listFiles ?>
        <?php
        case 'edit'  : // --------------------------------------------------
        ?>
            <div class="title">
                <?php echo $html->link($here.'?page='.$output['page'], $output['title'])?>
                <form action="<?php echo $here?>" method="post">
                    <?php echo $html->inputHidden('action', 'editName')?>
                    <?php echo $html->inputHidden('page', $output['page'])?>
                    <?php echo $html->submit(__('Rename'), 'class="renameButton"')?>
                </form>
            </div>
        </div>
        <div class="content">
            <?php if (isset($view)) { ?>
                <div class="view">
                    <?php echo $output['view']?>
                </div>
            <?php } ?>
            <form action="<?php echo $here?>" method="post">
                <?php echo $html->inputHidden('action', 'save')?>
                <?php echo $html->inputHidden('page', $output['page'])?>
                <?php echo $html->submit(__('Save'))?>
                <?php echo $html->reset(__('Reset'))?>
                <?php echo $html->button(__('Cancel'), 'onclick="editCancel()"')?>
                <div>
                    <?php echo $html->textarea('content', $output['content'], 'class="'.$output['contentEditBoxClass'].'"')?>
                </div>
                <?php echo $html->submit(__('Save'))?>
                <?php echo $html->reset(__('Reset'))?>
                <?php echo $html->button(__('Cancel'), 'onclick="editCancel()"')?>
            </form>
        </div>
        <?php break; // break case edit ?>
        <?php
        case 'editName': // --------------------------------------------------
        ?>
            <div class="title">
                <form action="<?php echo $here?>" method="post">
                    <?php echo $html->inputHidden('action', 'saveName')?>
                    <?php echo $html->inputHidden('page', $output['page'])?>
                    <?php echo $html->inputText('newName', $output['page'], 'size="80"')?>
                    <?php echo $html->submit(__('Save'))?>
                    <?php echo $html->reset(__('Reset'))?>
                    <?php echo $html->button(__('Cancel'), 'onclick="editCancel()"')?>
                </form>
            </div>
        </div>
        <div class="content">
            <?php if (isset($output['view'])) { ?>
                <form action="<?php echo $here?>" method="post">
                    <?php echo $html->inputHidden('action', 'edit')?>
                    <?php echo $html->inputHidden('page', $output['page'])?>
                    <?php echo $html->submit(__('Edit'))?>
                </form>
                <div class="view">
                    <?php echo $output['view']?>
                </div>
                <form action="<?php echo $here?>" method="post">
                    <?php echo $html->inputHidden('action', 'edit')?>
                    <?php echo $html->inputHidden('page', $output['page'])?>
                    <?php echo $html->submit(__('Edit'))?>
                </form>
            <?php } ?>
        </div>
        <?php break; // break case editName ?>
    <?php } // end switch action ?>
        <div class="footer">
            <?php echo $html->link('http://www.gnu.org/licenses/lgpl.txt', __('Licence'))?>
        </div>
        <div class="sign">
            <?php echo $html->link('http://www.kobashikawa.org/kcwiki/', 'kcWiki')?> 20081005 |
            <?php echo $html->link('mailto:akobashikawa@gmail.com', 'akobashikawa@gmail.com')?>
        </div>
</body>
</html>
<?php
/*
FEATURES
========
- UTF-8 support
- Link to wiki pages
- Include wiki pages
- Source code include support
- Executable code include support
- Themes
- Titles
- Lists
- Bolds, italics
- Password protected
- Upload files
- Delete, undelete, purge of files

REQUIREMENTS
============
- SVG
- Multipage version
- Syntaxis helper
- Particular theme overwritable
- Export
- System info: get_magic_quotes_gpc

HISTORY
=======
20081005
- Fixed bug about encode to utf8
- Fixed bug about render of titles before lists
- Margin 0 to lists and titles styles of default theme
- Fixed bug about consecutive titles render
- Change h1 style of default theme
- Deleted stripslashesr function
- Change sign style of default theme to hide sign
- Change default page name from kcwiki to Index
- Added link to LGPL licence
- Change footer style of default theme
- Fixed bug about parsing of http(s), ftp and mail links
- Fixed bug about italic and links
20081004
- New stripslashesr function in Html helper.
20081003
- Fixed bug in save about no error message when no login
- Change in save() to prevent magic quotes
- Change in save() saveName() to prevent invalid names
- Enhance framework schema to support input redefinition
- New function link in Html helper
- Using link to replace currents links
- Refactoring listFiles case to separate view
- Refactoring searchList to separate view
- Fixed error in _contentEncode()
20081002
- Fixed bug in new page creation
- Fixed bug about can not open iso-8859-1 text files
- Detection utf8 and encode using mbstring functions
- Detection utf8 and encode using native functions
- Enhanced list of files
- Factorizing common code in views
20080930
- Resorting themes code
- Some minor changes in default theme
- Changed login
- Reset and cancel buttons for edition
- New javascript method editCancel
- New Html helper methods reset, button, file
- Dictionary updated
- Upload file support
- List files
- Delete
- Undelete
- Purge
20080928
- Implemented referers
- Fixed password bug in edit case
- Changing login
20080925
- Using session to remember login
- Added logout button
- Resorting code
- Added redirect() in utils function
- Fixed bug about pre content presentation
20080921
- Simplification of framework
- Some resorting blocks of code
- CSS style for password box
- CSS style for content edit box
- CSS style for rename page button
- Fixed bug about default input action
20080919
- Search support
20080916
- Bold and italics support
20080915
- Fixed bug than lose style info of link ocurrences after rename page
20080906
- Ignoring .project
20080825
- Correction on documentation
- Correction on comments
- Added _view()
- Added _content()
- Correction of regexp used for update references in rename page case
- Titles format support
- Unsorted lists format support
- Sort lists format support
20080824
- Correction on documentation: Sintaxis, Requerimientos
20080704
- Initial svn import to
  http://svn.assembla.com/svn/kcwiki
20080703
- Rename project to kcWiki
- Fixed bug related to link presentation
20080608
- Fixed bugs related to includes presentation
- Basic support for url include
- Support for eval content
20080606
- Rename pages support
20080605
- Change in include support to support typed include support
20080529
- Image include support
- Image aligment support
- Support of style tag for includes 
20080526
- Enhance in theme per page support
20080525
- Enhance in includes presentation: Indentation, edit link.
- Includes type support: wikiPage, wikiText, prePage, preText
- Fixed bug about limitation in multiple paralel includes.
20080524
- Theme per page support
20080520
- Enhance syntax to wiki links and wiki includes.
- Basic external links support (http, https, ftp, mailto)
20080519
- Include wiki pages support, for unlimited levels, and empty or circular references prevention.
  I am proud for this feature :)
20080518
- Simple cicle view->edit->save->view performed
- Simple wiki parse
- Link to wiki pages support, with empty references manage.
20080517
- Design try page as natural controller.
20080516
- Start based upon sketch code who try to implement unix like chained process.

<!--
LICENCE
=======

kcWiki
A wiki
Copyright (C) 2008  Antonio Kobashikawa Carrasco - akobashikawa@gmail.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-->
*/
?>